#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"
#include "bmp.h"
#include "oledfont.h"
#include "oled_driver.h"
#include "countdown_timer.h"

// OLED硬件配置
#define OLED_I2C_ADDR     0x3C//0x78     // SH1106默认地址
#define I2C_MASTER_SCL_IO 27       // SCL引脚
#define I2C_MASTER_SDA_IO 26       // SDA引脚
#define I2C_MASTER_FREQ   400000   // I2C时钟频率(Hz)
#define OLED_WIDTH        128      // 屏幕宽度
#define OLED_HEIGHT       64       // 屏幕高度

QueueHandle_t disply_queue = NULL;

// 全局显示缓冲区
static uint8_t oled_buffer[OLED_WIDTH * OLED_HEIGHT / 8];
extern uint8_t local_ip[4];

// I2C初始化
void i2c_master_init() {
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ,
    };
    ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
    ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0));
}

// 发送命令序列
void sh1106_send_cmd(uint8_t cmd) {
    uint8_t buf[2] = {0x00, cmd}; // 控制字节+命令
    i2c_master_write_to_device(I2C_NUM_0, OLED_I2C_ADDR, buf, sizeof(buf), pdMS_TO_TICKS(1000));
}

// 初始化SH1106
void sh1106_init() {
    // 初始化命令序列
    const uint8_t init_cmds[] = {
        0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40,
        0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8, 0xDA, 0x12,
        0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6, 0xAF
    };
    
    for (int i=0; i<sizeof(init_cmds); i++) {
        sh1106_send_cmd(init_cmds[i]);
    }
}

// 设置显示位置（带2像素偏移修正）
void sh1106_set_pos(uint8_t page, uint8_t column) {
    column += 2; // SH1106专用偏移修正
    sh1106_send_cmd(0xB0 + page);              // 设置页地址
    sh1106_send_cmd(0x10 + (column >> 4));     // 列地址高4位
    sh1106_send_cmd(0x00 + (column & 0x0F));  // 列地址低4位
}

// 刷新整个屏幕
void sh1106_refresh() {
    for (uint8_t page=0; page<8; page++) {
        sh1106_set_pos(page, 0);
        uint8_t buf[129] = {0x40}; // 数据头字节
        memcpy(buf+1, oled_buffer + page*128, 128);
        i2c_master_write_to_device(I2C_NUM_0, OLED_I2C_ADDR, buf, sizeof(buf), pdMS_TO_TICKS(1000));
    }
}

// 清屏
void sh1106_clear() {
    memset(oled_buffer, 0, sizeof(oled_buffer));
    sh1106_refresh();
}

// 绘制像素点
void sh1106_draw_pixel(int x, int y, bool on) {
    if (x >= OLED_WIDTH || y >= OLED_HEIGHT) 
        return;
    if (on) 
        oled_buffer[x + (y/8)*128] |=  (1 << (y%8));
    else
        oled_buffer[x + (y/8)*128] &= ~(1 << (y%8));
}


//m^n
uint32_t OLED_Pow(uint8_t m,uint8_t n)
{
	uint32_t result=1;
	while(n--)
	{
	  result*=m;
	}
	return result;
}

//显示数字
//x,y :起点坐标
//num :要显示的数字
//len :数字的位数
//size:字体大小
//mode:0,反色显示;1,正常显示
// void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1,uint8_t mode)
// {
// 	uint8_t t,temp,m=0;
// 	if(size1==8)m=2;
// 	for(t=0;t<len;t++)
// 	{
// 		temp=(num/OLED_Pow(10,len-t-1))%10;
// 			if(temp==0)
// 			{
// 				sh1106_show_char(x+(size1/2+m)*t,y,'0',size1,mode);
//             }
// 			else 
// 			{
// 			  sh1106_show_char(x+(size1/2+m)*t,y,temp+'0',size1,mode);
// 			}
//   }
// }

//显示汉字
//x,y:起点坐标
//num:汉字对应的序号
//mode:0,反色显示;1,正常显示
void sh1106_show_Chiness(uint8_t x,uint8_t y,uint8_t num,uint8_t size1,uint8_t mode)
{
	uint8_t m,temp;
	uint8_t x0=x,y0=y;
	uint16_t i,size3=(size1/8+((size1%8)?1:0))*size1;  //得到字体一个字符对应点阵集所占的字节数
	for(i=0;i<size3;i++)
	{
		if(size1==16)
			{temp=Hzk1[num][i];}//调用16*16字体
		else if(size1==24)
			{temp=Hzk2[num][i];}//调用24*24字体
		// else if(size1==32)       
		// 	{temp=Hzk3[num][i];}//调用32*32字体
		// else if(size1==64)
		// 	{temp=Hzk4[num][i];}//调用64*64字体
		else 
            return;
		for(m=0;m<8;m++)
		{
			if(temp&0x01)
                sh1106_draw_pixel(x,y,mode);
			else 
                sh1106_draw_pixel(x,y,!mode);
			temp>>=1;
			y++;
		}
		x++;
		if((x-x0)==size1)
		{x=x0;y0=y0+8;}
		y=y0;
	}
}

//num 显示汉字的个数
//space 每一遍显示的间隔
//mode:0,反色显示;1,正常显示
// void sh1106_scroll_display(uint8_t num,uint8_t space,uint8_t mode)
// {
// 	uint8_t i,n,t=0,m=0,r;
// 	while(1)
// 	{
// 		if(m==0)
// 		{
// 	        sh1106_show_Chiness(128,24,t,16,mode); //写入一个汉字保存在OLED_GRAM[][]数组中
// 			t++;
// 		}
// 		if(t==num)
//         {
//             for(r=0;r<16*space;r++)      //显示间隔
//             {
//                 for(i=1;i<144;i++)
//                 {
//                     for(n=0;n<8;n++)
//                     {
//                         OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
//                     }
//                 }
//                 sh1106_refresh();
//             }
//             t=0;
//          }
// 		m++;
// 		if(m==16){m=0;}
// 		for(i=1;i<144;i++)   //实现左移
// 		{
// 			for(n=0;n<8;n++)
// 			{
// 				OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
// 			}
// 		}
// 		sh1106_refresh();
// 	}
// }


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size1:选择字体 6x8/6x12/8x16/12x24
//mode:0,反色显示;1,正常显示
void sh1106_show_char(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode)
{
	uint8_t i,m,temp,size2,chr1;
	uint8_t x0=x,y0=y;
	if(size1==8)size2=6;
	else size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
	chr1=chr-' ';  //计算偏移后的值
	for(i=0;i<size2;i++)
	{
		if(size1==8)
			{temp=asc2_0806[chr1][i];} //调用0806字体
		else if(size1==12)
            {temp=asc2_1206[chr1][i];} //调用1206字体
		// else if(size1==16)
        //     {temp=asc2_1608[chr1][i];} //调用1608字体
		// else if(size1==24)
        //     {temp=asc2_2412[chr1][i];} //调用2412字体
		else 
            return;
		for(m=0;m<8;m++)
		{
			if(temp&0x01)sh1106_draw_pixel(x,y,mode);
			else sh1106_draw_pixel(x,y,!mode);
			temp>>=1;
			y++;
		}
		x++;
		if((size1!=8)&&((x-x0)==size1/2))
		{x=x0;y0=y0+8;}
		y=y0;
  }
}

//显示字符串
//x,y:起点坐标  
//size1:字体大小 
//*chr:字符串起始地址 
//mode:0,反色显示;1,正常显示
void sh1106_show_string(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1,uint8_t mode)
{
	while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
	{
		sh1106_show_char(x,y,*chr,size1,mode);
		if(size1==8)x+=6;
		else x+=size1/2;
		chr++;
  }
  sh1106_refresh();
}


void sh1106_draw_picture(uint8_t x,uint8_t y,uint8_t sizex,uint8_t sizey,uint8_t BMP[],uint8_t mode)
{
    uint16_t j=0;
	uint8_t i,n,temp,m;
	uint8_t x0=x,y0=y;
	sizey=sizey/8+((sizey%8)?1:0);
	for(n=0;n<sizey;n++)
	{
		for(i=0;i<sizex;i++)
		{
            temp=BMP[j];
            j++;
            for(m=0;m<8;m++)
            {
                if(temp&0x01)sh1106_draw_pixel(x,y,mode);
                else sh1106_draw_pixel(x,y,!mode);
                temp>>=1;
                y++;
            }
            x++;
            if((x-x0)==sizex)
            {
                x=x0;
                y0=y0+8;
            }
            y=y0;
        }
	 }
     sh1106_refresh();
}

// 显示测试图案
void demo_pattern() {
    sh1106_clear();
    // 绘制边框
    for (int x=0; x<128; x++) {
        sh1106_draw_pixel(x, 0, true);
        sh1106_draw_pixel(x, 63, true);
    }
    for (int y=0; y<64; y++) {
        sh1106_draw_pixel(0, y, true);
        sh1106_draw_pixel(127, y, true);
    }
    // 绘制对角线
    for (int i=0; i<64; i++) {
        sh1106_draw_pixel(i*2, i, true);
        sh1106_draw_pixel(i*2, 63-i, true);
    }
    sh1106_refresh();
}

// I2C扫描工具
void i2c_scanner() {
    printf("\nI2C Scan result:\n");
    for (int addr=0x08; addr<=0x77; addr++) {
        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 50/portTICK_PERIOD_MS);
        i2c_cmd_link_delete(cmd);
        if (ret == ESP_OK) printf("find device: 0x%02X\n", addr);
    }
}


void oled_task(void* arg)
{
    uint32_t remain_time = 0;
    uint8_t display_type = 0;
    uint8_t hour = 0;
    uint8_t minute = 0;
    uint8_t second = 0;
    char temp_str[32];

    disply_queue = xQueueCreate(5, sizeof(uint32_t));

    // 初始化硬件
    i2c_master_init();
    i2c_scanner();  // 调试用I2C扫描

    // OLED初始化
    sh1106_init();
    sh1106_clear();

    #if 0
    sh1106_draw_picture(0,0,128,64,BMP1,1);
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    sh1106_clear();
    
    // 显示测试图案
    demo_pattern();
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    sh1106_clear();
    sh1106_show_string(8,16,(uint8_t*)"Waiting For End Work",12,1);
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    sh1106_clear();
    #endif

    sh1106_show_Chiness(30,15,0,24,1);//等
    sh1106_show_Chiness(58,15,1,24,1);//着
    sh1106_show_Chiness(85,15,2,24,1);//吧
    sh1106_refresh();

    for(;;)
    {
        if(xQueueReceive(disply_queue, &display_type, portMAX_DELAY))
        {
            switch (display_type)
            {
                case WORK_ON:
                    sh1106_clear();
                    sh1106_show_Chiness(30,15,3,24,1);
                    sh1106_show_Chiness(58,15,5,24,1);
                    sh1106_show_Chiness(85,15,6,24,1);
                    sh1106_refresh();
                    break;
                case WORK_OFF:
                    sh1106_clear();
                    sh1106_show_Chiness(30,15,4,24,1);//下
                    sh1106_show_Chiness(58,15,5,24,1);//班
                    sh1106_show_Chiness(85,15,6,24,1);//了
                    sh1106_refresh();
                    break;
                case WORK_COUNT_DOWN:
                    remain_time = getRemainTime();
                    hour = remain_time / 3600;
                    minute = (remain_time % 3600) / 60;
                    second = remain_time % 60;
                    memset(temp_str, 0, sizeof(temp_str));
                    snprintf(temp_str, 32, "%d:%02d:%02d", hour, minute, second);
                    sh1106_show_string(45, 40, (uint8_t*)temp_str,12,1);
                    break;
                case WORK_WAITING:
                    sh1106_show_Chiness(30,15,0,24,1);//等
                    sh1106_show_Chiness(58,15,1,24,1);//着
                    sh1106_show_Chiness(85,15,2,24,1);//吧
                    sh1106_refresh();
                    break;
                case WORK_NOID:
                    memset(temp_str, 0, sizeof(temp_str));
                    snprintf(temp_str, 32, "%d.%d.%d.%d", local_ip[0], local_ip[1], local_ip[2], local_ip[3]);
                    sh1106_show_string(34, 40, (uint8_t*)temp_str,12,1);
                    break;
                default:
                    break;
            }
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
